/*
 * Copyright (c) 2025 Huawei Device Co., Ltd.
 * Licensed under the Apache License, Version 2.0 (the "License");
 * you may not use this file except in compliance with the License.
 * You may obtain a copy of the License at
 *
 *     http://www.apache.org/licenses/LICENSE-2.0
 *
 * Unless required by applicable law or agreed to in writing, software
 * distributed under the License is distributed on an "AS IS" BASIS,
 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
 * See the License for the specific language governing permissions and
 * limitations under the License.
 */

import SerializationPathUtil from '../../../utils/SerializationPathUtil';
import { ITaskContext } from '../../..';

interface ImportInfo {
  modulePath: string;
  importedNames: string[];
  isDefaultImport: boolean;
  isNamespaceImport: boolean;
}

export class ImportManager {
  private imports: Map<string, ImportInfo> = new Map();
  private defaultImports: Map<string, string> = new Map();
  // 跟踪类型名称到模块路径的映射，用于去重
  private typeToModulePath: Map<string, string> = new Map();
  // 路径映射器
  private context: ITaskContext | null = null;

  registerCoreImports(interfaceNames: string[]): void {
    const coreModule = '@hadss/turbo-trans-core';

    for (const interfaceName of interfaceNames) {
      this.registerCustomImport(coreModule, interfaceName);
    }
  }

  registerJsonImports(names: string[]): void {
    const jsonModule = '@hadss/turbo-trans-json';

    for (const name of names) {
      this.registerCustomImport(jsonModule, name);
    }
  }

  registerArkTSImports(names: string[]) {
    const arkTSModule = '@kit.ArkTS';

    for (const name of names) {
      this.registerCustomImport(arkTSModule, name);
    }
  }

  registerCustomImport(modulePath: string, importedName: string): void {
    // 智能去重：检查是否已有同名类型的更好路径
    if (this.typeToModulePath.has(importedName)) {
      const existingModulePath = this.typeToModulePath.get(importedName)!;

      // 优先级：包名路径 > 模块化路径 > 相对路径
      // 包名路径来自用户源文件的原始导入，应该保持不变

      // 如果已存在的是包名路径，忽略当前注册（保持用户原始导入）
      if (this.isPackagePath(existingModulePath)) {
        return;
      }

      // 如果当前是包名路径，替换已存在的路径
      if (this.isPackagePath(modulePath)) {
        this.removeImportFromModule(existingModulePath, importedName);
        this.typeToModulePath.set(importedName, modulePath);
      } else if (this.isModularPath(modulePath) && this.isRelativePath(existingModulePath)) {
        // 如果当前路径是模块化路径，而已存在的是相对路径，则替换
        this.removeImportFromModule(existingModulePath, importedName);
        this.typeToModulePath.set(importedName, modulePath);
      } else if (this.isRelativePath(modulePath) && this.isModularPath(existingModulePath)) {
        // 如果当前是相对路径，已存在的是模块化路径，则忽略当前注册
        return;
      } else if (this.isModularPath(modulePath) && this.isModularPath(existingModulePath)) {
        // 如果两者都是模块化路径，保持已存在的（先注册的优先）
        return;
      }
    } else {
      // 首次注册该类型
      this.typeToModulePath.set(importedName, modulePath);
    }

    if (this.imports.has(modulePath)) {
      const existingInfo = this.imports.get(modulePath)!;
      const names = new Set(existingInfo.importedNames);
      names.add(importedName);

      this.imports.set(modulePath, {
        ...existingInfo,
        importedNames: Array.from(names)
      });
    } else {
      this.imports.set(modulePath, {
        modulePath,
        importedNames: [importedName],
        isDefaultImport: false,
        isNamespaceImport: false
      });
    }
  }

  registerDefaultImport(modulePath: string, importedName: string): void {
    if (this.defaultImports.has(modulePath)) {
      return;
    }

    this.defaultImports.set(modulePath, importedName);
  }

  /**
   * 判断是否为模块化路径（不以 . 或 / 开头，不是 @开头的包名）
   */
  private isModularPath(modulePath: string): boolean {
    return !modulePath.startsWith('.') && 
           !modulePath.startsWith('/') && 
           !modulePath.startsWith('@') &&
           modulePath.includes('/');
  }

  private isRelativePath(modulePath: string): boolean {
    return modulePath.startsWith('./') || modulePath.startsWith('../');
  }

  /**
   * 判断是否为包名路径（npm包或本地包名）
   * 包括：
   * - 简单包名：'common'、'lodash'（不包含 /）
   * - Scoped package：'@hadss/turbo-trans-core'、'@org/package'（以 @ 开头）
   */
  private isPackagePath(modulePath: string): boolean {
    // 相对路径不是包名
    if (modulePath.startsWith('.') || modulePath.startsWith('/')) {
      return false;
    }
    // @ 开头的是 scoped package
    if (modulePath.startsWith('@')) {
      return true;
    }
    // 不包含 / 的是简单包名（如 'common'、'lodash'）
    // 包含 / 的是模块化路径（如 'sampleentry/common/models/UserStatus'）
    return !modulePath.includes('/');
  }

  private removeImportFromModule(modulePath: string, importedName: string): void {
    if (this.imports.has(modulePath)) {
      const existingInfo = this.imports.get(modulePath)!;
      const filteredNames = existingInfo.importedNames.filter(name => name !== importedName);
      
      if (filteredNames.length === 0) {
        // 如果该模块没有其他导入，则删除整个模块
        this.imports.delete(modulePath);
      } else {
        // 否则只更新导入列表
        this.imports.set(modulePath, {
          ...existingInfo,
          importedNames: filteredNames
        });
      }
    }
  }

  getImportDeclarations() {
    const imports: Array<{ specifier: string, names: string[] }> = [];
    for (const [specifier, infos] of this.imports) {
      imports.push({ specifier: specifier, names: infos.importedNames });
    }
    return imports;
  }

  getDefaultImport(): Array<{ specifier: string, name: string }> {
    const defaultImports: Array<{ specifier: string, name: string }> = [];
    for (const [specifier, info] of this.defaultImports) {
      defaultImports.push({ specifier: specifier, name: info });
    }
    return defaultImports;
  }

  clear(): void {
    this.imports.clear();
    this.typeToModulePath.clear();
  }

  /**
   * 设置路径映射器
   *
   * @param context 任务上下文
   */
  setContext(context: ITaskContext): void {
    this.context = context;
  }

  /**
   * 注册自定义类型导入（使用模块化路径）
   * @param customTypeFilePath 自定义类型文件的绝对路径
   * @param typeName 类型名称
   */
  registerCustomTypeImport(customTypeFilePath: string, typeName: string): void {
    // 使用路径映射器计算模块化路径
    const modularImportPath = SerializationPathUtil.calculateModularImportPath(customTypeFilePath, this.context!);

    this.registerCustomImport(modularImportPath, typeName);
  }

  /**
   * 注册临时序列化器导入（从 tempSerializer/index.ets）
   * @param serializerName 序列化器名称（如 "PersonSerializer"）
   */
  registerTempSerializerImport(serializerName: string): void {
    // 计算 tempSerializer 目录的模块化路径
    const outputRoot = this.context!.getOutputRoot();
    const tempSerializerPath = SerializationPathUtil.pathResolve(outputRoot, 'tempSerializer');
    const modularImportPath = SerializationPathUtil.calculateModularImportPath(tempSerializerPath, this.context!);

    this.registerCustomImport(modularImportPath, serializerName);
  }

  /**
   * 注册跨模块序列化器导入
   * 用于跨模块的 @Serializable 类，序列化器在目标模块的 generated 目录中
   *
   * @param sourceFilePath 源文件的绝对路径（如 .../common/src/main/ets/models/Product.ets）
   * @param packageName 目标模块名（如 'common'）
   * @param serializerName 序列化器名称（如 'ProductSerializer'）
   *
   * @example
   * 输入: sourceFilePath = '.../common/src/main/ets/models/Product.ets', packageName = 'common'
   * 输出: 'common/src/generated/ets/models/Product'
   */
  registerCrossModuleSerializerImport(sourceFilePath: string, packageName: string, serializerName: string): void {
    // 从源文件路径中提取相对路径部分
    // 源文件: .../common/src/main/ets/models/Product.ets
    // 目标: common/src/generated/ets/models/Product

    // 查找 src/main/ets 的位置
    const srcMainEtsIndex = sourceFilePath.indexOf('src/main/ets');
    if (srcMainEtsIndex === -1) {
      // 回退到常规导入
      this.registerCustomTypeImport(sourceFilePath, serializerName);
      return;
    }

    // 提取 ets 之后的相对路径（如 models/Product.ets）
    const etsRelativePath = sourceFilePath.substring(srcMainEtsIndex + 'src/main/ets/'.length);

    // 移除文件扩展名
    const pathWithoutExt = SerializationPathUtil.removeFileExtension(etsRelativePath);

    // 构建跨模块序列化器导入路径: packageName/src/generated/ets/relativePath
    const crossModuleSerializerPath = `${packageName}/src/generated/ets/${pathWithoutExt}`;

    this.registerCustomImport(crossModuleSerializerPath, serializerName);
  }
}
